﻿/////////////////////////////////////////////////////////////////
//
// Physics Helper XAML
//
// by Andy Beaulieu - http://www.andybeaulieu.com
//
// LICENSE: This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ANY 
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
/////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FarseerPhysics.Dynamics.Joints;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
using WinUI = Windows.UI;

namespace Spritehand.FarseerHelper
{
    /// <summary>
    /// Represents a Joint to be added into the physics simulation
    /// </summary>
    public class PhysicsJoint : Canvas
    {
        private Ellipse _ellDesign;

        public PhysicsJoint()
        {
            this.Width = 8;
            this.Height = 8;
            _ellDesign = new Ellipse();
            _ellDesign.Width = 8;
            _ellDesign.Height = 8;
            _ellDesign.Stroke = new SolidColorBrush(WinUI.Colors.White);
            this.Children.Add(_ellDesign);

            if (Utilities.IsDesignMode)
                return;

            this.Loaded += new RoutedEventHandler(PhysicsJoint_Loaded);
        }

        void PhysicsJoint_Loaded(object sender, RoutedEventArgs e)
        {
            PhysicsCanvas _physCanvas = PhysicsUtilities.FindPhysicsCanvas(this);

            _physCanvas.AddPhysicsJoint(this);

            this.Loaded -= PhysicsJoint_Loaded;
        }

        private string _bodyOne = string.Empty;
        /// <summary>
        /// The first body to join with this joint
        /// </summary>
        public string BodyOne
        {
            get { return _bodyOne; }
            set { _bodyOne = value; }
        }

        private string _bodyTwo = string.Empty;
        /// <summary>
        /// The second body to join with this joint
        /// </summary>
        public string BodyTwo
        {
            get { return _bodyTwo; }
            set { _bodyTwo = value; }
        }

        private bool _angleSpringEnabled = false;
        /// <summary>
        /// If true then the joint will spring back to position
        /// </summary>
        public bool AngleSpringEnabled
        {
            get { return _angleSpringEnabled; }
            set { _angleSpringEnabled = value; }
        }

        private double _angleLowerLimit = -1;
        public double AngleLowerLimit
        {
            get { return _angleLowerLimit; }
            set { _angleLowerLimit = value; }
        }

        private double _angleUpperLimit = -1;
        /// <summary>
        /// The angle, in degrees of the joint's upper limit
        /// </summary>
        public double AngleUpperLimit
        {
            get { return _angleUpperLimit; }
            set { _angleUpperLimit = value; }
        }

        private double _angleSpringConstant = 0.8;
        /// <summary>
        /// A higher number makes the angle spring more "stiff", lower number more "soft"
        /// </summary>
        public double AngleSpringConstant
        {
            get { return _angleSpringConstant; }
            set { _angleSpringConstant = value; }
        }

        private int _collisionGroup = 0;
        /// <summary>
        /// Sprites within the same collision group DO NOT fire collision events.
        /// </summary>
        public int CollisionGroup
        {
            get { return _collisionGroup; }
            set { _collisionGroup = value; }
        }

        private bool _isWeldJoint = false;
        /// <summary>
        /// A Weld joint simply joins two bodies together
        /// </summary>
        public bool IsWeldJoint
        {
            get
            {
                return _isWeldJoint;
            }
            set
            {
                _isWeldJoint = value;
            }
        }

        private bool _isDistanceJoint = false;
        /// <summary>
        /// Distance Joints keep objects apart a given length
        /// </summary>
        public bool IsDistanceJoint
        {
            get
            {
                return _isDistanceJoint;
            }
            set
            {
                _isDistanceJoint = value;
            }
        }

        /// <summary>
        /// Gets the point (screen coordinates) of the joint location
        /// </summary>
        /// <returns></returns>
        public Point GetCenter()
        {
            // we may need to figure in offset
            double offSetLeft = 0;
            double offSetTop = 0;

            FrameworkElement parent = (this.Parent as FrameworkElement);
            while (parent != null)
            {

                double incLeft = Convert.ToDouble(parent.GetValue(Canvas.LeftProperty));
                double incTop = Convert.ToDouble(parent.GetValue(Canvas.TopProperty));

                // In WPF the parent top/left can be NaN which causes problems elsewhere
                offSetLeft += double.IsNaN(incLeft) ? 0 : incLeft;
                offSetTop += double.IsNaN(incTop) ? 0 : incTop;

                parent = parent.Parent as FrameworkElement;
            }

            Point pt = new Point();


            pt.X = (double)this.GetValue(Canvas.LeftProperty) + (this.Width / 2) + offSetLeft;
            pt.Y = (double)this.GetValue(Canvas.TopProperty) + (this.Height / 2) + offSetTop;

            return pt;
        }
    }
}
